/*
 * Copyright (C) 2011 Nicola Bonzanni
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nl.vu.few.ibivu.jlemon.listgraph;

import java.util.Iterator;
import java.util.Map;

import nl.vu.few.ibivu.jlemon.IncomingArcIterator;
import nl.vu.few.ibivu.jlemon.NodeIterator;
import nl.vu.few.ibivu.jlemon.OutgoingArcIterator;
import nl.vu.few.ibivu.jlemon.concepts.PetriNet;

public abstract class ListPetriNet<T extends Comparable<T>> extends ListDigraph implements PetriNet<Node, ListDigraph.Arc, T> {
	
	private static final long serialVersionUID = 1L;

	@Override
	public Iterator<Node> transitionIterator() {
		return new Iterator<Node>() {
			Iterator<Node> iterator = new NodeIterator<Node>(ListPetriNet.this);
			Node next = nextTransition();
			
			@Override
			public boolean hasNext() {
				return (next != null);
			}

			private Node nextTransition() {
				Node node;
				while (iterator.hasNext()) {
					if (isTransition(node = iterator.next())) {
						return node;
					}
				}
				return null;
			}

			@Override
			public Node next() {
				Node current = next;
				next = nextTransition();
				return current;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
			
		};
	}

	@Override
	public Iterator<Node> placeIterator() {
		return new Iterator<Node>() {
			Iterator<Node> iterator = new NodeIterator<Node>(ListPetriNet.this);
			Node next = nextPlace();
			
			@Override
			public boolean hasNext() {
				return (next != null);
			}

			private Node nextPlace() {
				Node node;
				while (iterator.hasNext()) {
					if (isPlace(node = iterator.next())) {
						return node;
					}
				}
				return null;
			}

			@Override
			public Node next() {
				Node current = next;
				next = nextPlace();
				return current;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
			
		};
	}

	@Override
	public Iterator<Node> inputPlaceIterator(final Node transition) {
		return new Iterator<Node>() {
			Iterator<Arc> iterator = new IncomingArcIterator<Arc>(ListPetriNet.this, transition);
			Node next = nextPlace();
			
			@Override
			public boolean hasNext() {
				return (next != null);
			}

			private Node nextPlace() {
				Node node;
				while (iterator.hasNext()) {
					if (isPlace(node = source(iterator.next()))) {
						return node;
					}
				}
				return null;
			}

			@Override
			public Node next() {
				Node current = next;
				next = nextPlace();
				return current;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
			
		};
	}

	@Override
	public Iterator<Node> outputPlaceIterator(final Node transition) {
		return new Iterator<Node>() {
			Iterator<Arc> iterator = new OutgoingArcIterator<Arc>(ListPetriNet.this, transition);
			Node next = nextPlace();
			
			@Override
			public boolean hasNext() {
				return (next != null);
			}

			private Node nextPlace() {
				Node node;
				while (iterator.hasNext()) {
					if (isPlace(node = target(iterator.next()))) {
						return node;
					}
				}
				return null;
			}

			@Override
			public Node next() {
				Node current = next;
				next = nextPlace();
				return current;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
			
		};
	}

	@Override
	public Iterator<Node> enabledTransitionIterator(final Map<Node, T> marking) {
		return new Iterator<Node> () {
			Iterator<Node> iterator = transitionIterator();
			Node next = nextEnabled();
			
			@Override
			public boolean hasNext() {
				return (next != null);
			}

			@Override
			public Node next() {
				Node current = next;
				next = nextEnabled();
				return current;
			}
			
			private Node nextEnabled() {
				Node node;
				while (iterator.hasNext()) {
					if (isEnabled(marking, node = iterator.next())) {
						return node;
					}
				}
				return null;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}
}
